package linker

import (
	"debug/elf"
)

// OutPutSection 处理 Section 的输出
// Section 来自于不同的 Object 文件 中相同的 Section 合并到一起
type OutPutSection struct {
	Chunk
	Members []*InputSection
	Index   uint32
}

// NewOutPutSection OutPutSection 的构造函数
// 根据传递进来的参数进行一些初始化
func NewOutPutSection(name string, typ uint32, flags uint64, index uint32) *OutPutSection {
	o := &OutPutSection{Chunk: NewChunk()}

	o.Name = name
	o.SectionHeader.Type = typ
	o.SectionHeader.Flags = flags
	o.Index = index

	return o
}

// CopyBuf 拷贝 OutPutSection 中的内容到 context 中的 Buf
func (o *OutPutSection) CopyBuf(ctx *Context) {
	// 越过不占用磁盘空间的 Section
	if o.SectionHeader.Type == uint32(elf.SHT_NOBITS) {
		return
	}

	base := ctx.Buf[o.SectionHeader.Offset:]
	for _, insection := range o.Members {
		insection.WriteTo(ctx, base[insection.Offset:])
	}
}

// GetOutPutSection 根据参数获取对应的 OutPutSection
// 主要针对 多个 InPutSection 对一个 OutPutSection
// 如果已经存在就直接返回 否则创建一个新的 OutPutSection
func GetOutPutSection(ctx *Context, name string, typ, flags uint64) *OutPutSection {
	name = GetOutPutName(name, flags)

	flags = flags &^ uint64(elf.SHF_GROUP) &^
		uint64(elf.SHF_COMPRESSED) &^ uint64(elf.SHF_LINK_ORDER)

	find := func() *OutPutSection {
		for _, outsection := range ctx.OutPutSections {
			if name == outsection.Name && typ == uint64(outsection.SectionHeader.Type) && flags == outsection.SectionHeader.Flags {
				return outsection
			}
		}
		return nil
	}

	// 存在 直接返回
	if osec := find(); osec != nil {
		return osec
	}

	// 不存在 创建新的 OutPutSection
	osec := NewOutPutSection(name, uint32(typ), flags, uint32(len(ctx.OutPutSections)))

	ctx.OutPutSections = append(ctx.OutPutSections, osec)

	return osec
}
